/*
 *  Copyright (C) 1993  Robert Davis
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of Version 2, or any later version, of 
 *  the GNU General Public License as published by the Free Software 
 *  Foundation.
 */

static char RCSId[]="$Id: Inspector.m,v 1.13 1993/05/18 03:55:15 davis Exp $";


#import <appkit/Application.h>
#import <appkit/Button.h>
#import <appkit/Matrix.h>
#import <appkit/Panel.h>
#import <appkit/Pasteboard.h>
#import <appkit/publicWraps.h>	/* NXBeep()		*/

#import <dpsclient/wraps.h>

#import "AxesPane.h"
#import "DataPane.h"
#import "GeneralPane.h"
#import "Gnuplot.h"
#import "GnuplotPlot.h"
#import "Inspector.h"
#import "NoPane.h"
#import "Pane.h"
#import "Status.h"
#import "ThreeDPane.h"


@interface Inspector (Private)

- _setupPane:(Pane *)aPane;
- _selectPane:(int)aPane;
- _swapPane:(Pane *)new;
- _determineNewStatusAndDoc;
- _updateForce:(BOOL)force all:(BOOL)all;

@end



@implementation Inspector


- init
{
    const char	*validSend[] = {NXAsciiPboardType, NULL};
    const char	*validReturn[] = {NXAsciiPboardType, NULL};

    [super init];

    [NXApp loadNibSection: "Inspector.nib" 
		    owner: self
		withNames: NO
		 fromZone: [self zone]];

    [window setFrameUsingName:"InspectorPanel"];
    [window setFrameAutosaveName:"InspectorPanel"];

    [NXApp registerServicesMenuSendTypes: validSend
                          andReturnTypes: validReturn];

    [[window contentView] allocateGState];

    return self;
}


- free
{
    [window free];
    [noPane free];
    [generalPane free];
    [dataPane free];
    [axesPane free];
    [threeDPane free];

    return [super free];
}


- window
{
    return window;
}



- showPane:sender
{
    if (status)
	[self _selectPane:[sender selectedTag]];
    return self;
}


/* 
 *  Services.  The Inspector instance is the inspector panel's 
 *  delegate, so these methods work when the inspector panel is the 
 *  key window.  We pass service requests on to the current 
 *  GnuplotPlot so that the filename of the current doc can always be 
 *  offered to servers, even when the inspector is the key window.
 */
- validRequestorForSendType:(NXAtom)sendType andReturnType:(NXAtom) returnType
{
    return [gnuplotPlot validRequestorForSendType:sendType 
				    andReturnType:returnType];
}


- (BOOL)writeSelectionToPasteboard:pboard types:(NXAtom *)types
{
    return [gnuplotPlot writeSelectionToPasteboard:pboard types:types];
}



/* 
 *  This method is similar to -windowDidUpdate except that it forces 
 *  ALL panes to update instead of just allowing the current pane to 
 *  possibly update.  This is necessary to keep a pane's OptionsPanels 
 *  up-to-date even when that pane is not selected.  (This is only a 
 *  problem after such operations as "Revert to Saved" when NXApp's 
 *  delegate must send this method.)
 */
- update
{
    return [self _updateForce:YES all:YES];
}



/*  
 *  The user can force a plot by pressing the Plot button in the 
 *  Inspector. 
 */
- doPlot:sender
{
    if (gnuplotPlot)
	[gnuplotPlot plot:self];
    else
	NXBeep();

    return self;
}



/*  
 *  This method is similar to -update except that it updates only the 
 *  current pane, and allows it to decide whether or not it should 
 *  update itself instead of forcing it to update.
 */
- windowDidUpdate:sender
{
    return [self _updateForce:NO all:NO];
}



- selectPane:(int)aPane
{
    if (aPane != NO_INSPECTOR)
	[buttonMatrix selectCellWithTag:aPane];

    [self _selectPane:aPane];
    return self;
}



// Shuts up the compiler about unused RCSId
- (const char *) rcsid
{
    return RCSId;
}


@end


@implementation Inspector (Private)

- _setupPane:(Pane *)aPane
{
    if (aPane) {
	View	*panesView = [aPane view];

	[[window contentView] addSubview: panesView];
	[[panesView allocateGState] lockFocus];
	[panesView unlockFocus];
	[panesView moveTo:0:30];
    }

    return self;
}
	

- _selectPane:(int)aPane
{
    if (![window isVisible])
	[self _determineNewStatusAndDoc];

    if (!status)
	aPane = NO_INSPECTOR;

    switch (aPane) {

    case GENERAL_INSPECTOR:
	if (!generalPane) {
	    generalPane = [[GeneralPane allocFromZone:[self zone]] init];
	    [self _setupPane:generalPane];
	}
	[self _swapPane:generalPane];
	break;

    case DATA_INSPECTOR:
	if (!dataPane) {
	    dataPane = [[DataPane allocFromZone:[self zone]] init];
	    [self _setupPane:dataPane];
	}
	[self _swapPane:dataPane];
	break;

    case AXES_INSPECTOR:
	if (!axesPane) {
	    axesPane = [[AxesPane allocFromZone:[self zone]] init];
	    [self _setupPane:axesPane];
	}
	[self _swapPane:axesPane];
	break;

    case THREED_INSPECTOR:
	if (!threeDPane) {
	    threeDPane = [[ThreeDPane allocFromZone:[self zone]] init];
	    [self _setupPane:threeDPane];
	}
	[self _swapPane:threeDPane];
	break;

    default:
	if (!noPane) {
	    noPane = [[NoPane allocFromZone:[self zone]] init];
	    [self _setupPane:noPane];
	}
	[self _swapPane:noPane];
	break;

    }

    return self;
}


- _swapPane:(Pane *)new
{
    /*  
     *  If "new" is nil, we look at the button matrix
     *  to determine which inspector to swap in.
     */
    
    if (!new)
	switch ([buttonMatrix selectedTag]) {
	case GENERAL_INSPECTOR:
	    new = generalPane; break;
	case DATA_INSPECTOR:
	    new = dataPane; break;
	case AXES_INSPECTOR:
	    new = axesPane; break;
	case THREED_INSPECTOR:
	    new = threeDPane; break;
	default:
	    new = noPane; break;
	}
	    

    /*  
     *  Now, if the new pane is not already visible,
     *  move it into the inspector panel.
     */
    
    if (new != currentPane) {

	[[window contentView] replaceSubview:[currentPane view]
					with:[new view]];
	[currentPane didSwapOut:self];
	[[new didSwapIn:self] updateStatus:status doc:gnuplotPlot];
	[window display];

	[window setTitle:[new title]];
	[window setMiniwindowIcon:[new icon]];

	currentPane = new;

    }

    return self;
}


- _determineNewStatusAndDoc
{
    Window	*mainWindow = [NXApp mainWindow];

    /*  Set instance variables that indicate the current doc.  */

    if (mainWindow)  {
	gnuplotPlot = [mainWindow delegate];
	status = [gnuplotPlot status];
    } else {
	if (gnuplotPlot = [[NXApp delegate] currentDoc])
	    status = [gnuplotPlot status];
	else
	    status = nil;
    }

    return self;
}


- _updateForce:(BOOL)force all:(BOOL)all
{
    BOOL	needsRedisplay = NO;

    [self _determineNewStatusAndDoc];
    [window disableDisplay];

    if (!status) {			/* No current selection		*/

	[self selectPane:NO_INSPECTOR];
	needsRedisplay = YES;

    } else {				/* Update/replace controls	*/

	if (force) {

	    if (all) {

		needsRedisplay = [noPane forceUpdateStatus:status
						   doc:gnuplotPlot]? YES :NO;

		needsRedisplay = ([generalPane forceUpdateStatus:status
				  doc:gnuplotPlot]? YES :NO) || needsRedisplay;

		needsRedisplay = ([dataPane forceUpdateStatus:status
				  doc:gnuplotPlot]? YES :NO) || needsRedisplay;

		needsRedisplay = ([axesPane forceUpdateStatus:status
				  doc:gnuplotPlot]? YES :NO) || needsRedisplay;

		needsRedisplay = ([threeDPane forceUpdateStatus:status
				  doc:gnuplotPlot]? YES :NO) || needsRedisplay;

	    } else

		needsRedisplay = [currentPane forceUpdateStatus:status
			      doc:gnuplotPlot]? YES :NO;

	} else

	    needsRedisplay = [currentPane updateStatus:status doc:gnuplotPlot]?
								YES :NO;
	if (currentPane == noPane)
	    [self selectPane:[buttonMatrix selectedTag]];

    }

    [window reenableDisplay];
    if (needsRedisplay)
	[window display];

    /* 
     *  We disable the plot button if
     * 		1) No current status, or
     * 		2) Current plot's status reports that it can't plot
     */
    [plotButton setEnabled:status && [status canPlot]];
    
    return self;



}

@end
